"Badges" in Sway Window Titles
I have been using network namespaces and I thought it would be cool to be able to tell the namespace of a window by just looking at it. This post explores how to do that in sway.
Instead of showing how to do it for network namespaces, a slightly more general version is developed where the colour is chosen according to some condition on the pid of the window.
I originally intended to change the windows title bar and border colours. Unfortunately this feature is not available and it seems it will never be.
It is nevertheless possible to have custom background colours for
the title, so it looks like a badge,
using pango
markup with sway's title_format command.
This can be achieved with the following steps
- Subscribe to window events
- Extract program's pid when a new window is created
- Change the window title format depending on some condition on the pid
For step 1, you can monitor sway events with the swaymsg
command. We are interested in window events. The following command
prints to stdout information about window events as they occur
swaymsg -mt subscribe '["window"]'
In step 2, it is necessary to process the output from step 1. Since it is in JSON format jq is the perfect tool for the job.
In order to filter new window events from the output, take events for which the change field is "new" and extract the corresponding pid.
swaymsg -mt subscribe '["window"]' |
jq --unbuffered 'select(.change == "new") | .container.pid'
The --unbuffered option is necessary for the pid to be
printed as soon as the window appears.
For step 3, the title can be customized using
sway's title_format command. To be able to change the
background colour you have to enable pango with
sway's font command. For example
swaymsg 'font pango:monospace 10'
You can use the font of your preference instead of just
'monospace'. If you would like pango to be enabled by default when
sway starts add the font command to your sway
configuration file.
Now you can
use pango
markup to modify the format of the title. The following script
runs a new foot
process, saves the pid and uses for_window
and title_format to set the background colour once the
window shows on the screen.
#!/usr/bin/bash
foot &
pid=$!
swaymsg "for_window [pid=\"$pid\"] title_format \"<span background='#ff0000'> %title </span>\""
The idea now is to read each line in the output of step 2, which
corresponds to the pid of the most recent new window, check some
condition on that pid and if it is satisfied run something on the
lines of the swaymsg command above.
An important change in the final version is to take
away for_window. This is because
when for_window is used it applies to new windows and
when it is not used it applies to existing windows. In the foot
example the window had not yet appeared when the pid was captured.
Let's say we want all new windows with an even pid to have a title with a green background. Here is a way to do it
#!/usr/bin/bash
color="#00ff00"
swaymsg -mt subscribe '["window"]' |
jq --unbuffered 'select(.change == "new") | .container.pid' |
while read -r pid
do
if [ $(($pid % 2)) -eq 0 ]
then
swaymsg "[pid=\"$pid\"] title_format \"<span background='$color'> %title </span>\""
fi
done
While the script runs, open some terminals and note that only some of them (those with an even pid) have a green background in the title.
You can modify the condition above so that you can assign different colours on more interesting conditions. My original purpose was to have different colours for different namespaces. If you are looking to do something similar the way to get the name of the network namespace for a particular pid is
ip netns identify <pid>